package com.runvp.netty.server;

import com.runvp.common.model.tcp.MessageReceiveBody;
import com.runvp.common.model.tcp.MessageResBody;
import com.runvp.netty.constant.NettyConstant;
import com.runvp.netty.server.handler.BizHandle;
import com.runvp.netty.server.handler.SendMsgHandle;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;


/**
 * *
 * NettyServerHandler 业务处理Handler
 *
 * @author xkk
 * @Date 2020/07/13 07:13
 **/
@Component
@Sharable
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {


    @Autowired
    private BizHandle bizHandle;

    private SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        MessageReceiveBody parseBody;
        log.info("2-接收到设备发送的报文:{}",msg);
//        log.info("<<<<===============数据转换===============>>>>");
        try {
            parseBody = (MessageReceiveBody) msg;
        } catch (Exception e) {
            log.error("2-<<<<===============转换失败->>执行中断===============>>>> msg: {}", e);
            return;
        }
//        log.info("转换后数据：{}",JSONObject.toJSONString(parseBody));
//        log.info("<<<<===============转换结束===============>>>>");
//        log.info("<<<<===============业务处理===============>>>>");
        try {
            //业务处理
            Channel channel = ctx.channel();
            String cid = NettyConstant.getChannelId(channel);
            log.info("2-本次通道id:【{}】,是否存在上线时建立的链接中:【{}】",cid,NettyConstant.channelIdMap.containsKey(cid));
            bizHandle.setChannel(channel);
            bizHandle.setParseBody(parseBody);
            MessageResBody resBody = bizHandle.handle();
            if (null == resBody) {
                log.warn("3-响应信息为空,执行结束");
                return;
            }
            byte[] bytes = SendMsgHandle.buildSendMsg(resBody);
            if (null == bytes) {
                log.warn("3-响应信息为空,执行结束");
                return;
            }
            ByteBuf buff = Unpooled.buffer();//netty需要用ByteBuf传输
            buff.writeBytes(bytes);//对接需要16进制
            ctx.write(buff);
            ctx.flush();
//            log.info("<<<<===============处理结束===============>>>>");
        } catch (Exception e) {
            log.error("3-业务处理异常,执行中断:{}", e.getMessage());
        }finally {
            ReferenceCountUtil.release(msg);
        }
    }
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        // 这里可以做清理工作，确保所有的消息都已经接收并处理完毕
        ctx.flush();
    }
    /**
     * 建立连接以后第一个调用的方法
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        String cid = NettyConstant.getChannelId(channel);
        log.info("设备上线后建立的第一个通道id:【{}】",cid);
        NettyConstant.channelInitAdd(channel);
        //打印 ChannelGroup中的人数
        statusInfo();
    }

    private void statusInfo() {
        log.info("当前在线组:【{}】,all通道数：【{}】,在线通道数：【{}】,正常通道数：【{}】" , NettyConstant.all.size(),NettyConstant.channels.size(),NettyConstant.channels.name(),NettyConstant.getNormals().size());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("设备连接成功: {}",NettyConstant.getClientIpPort(ctx.channel()));
        super.channelActive(ctx);
        statusInfo();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        //这里 ChannelGroup 底层封装会遍历给所有的channel发送消息
        log.info("设备连接断开: {}",NettyConstant.getClientIpPort(channel));
        super.channelInactive(ctx);
        ctx.disconnect(ctx.newPromise());
        ctx.close();
        removeSnChannel(channel);
        statusInfo();
    }



    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws InterruptedException {
        Channel channel = ctx.channel();
        //这里 ChannelGroup 底层封装会遍历给所有的channel发送消息
        String cp = NettyConstant.getClientIpPort(channel);
        log.error("连接【{}】发生异常:{}", cp, cause);
        ctx.disconnect(ctx.newPromise());
        ctx.close();
        removeSnChannel(channel);
        statusInfo();
    }

    /**
     * 断开连接会触发该消息
     * 同时当前channel 也会自动从ChannelGroup中被移除
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        String cp = NettyConstant.getClientIpPort(channel);
        ctx.disconnect(ctx.newPromise());
        ctx.close();
        removeSnChannel(channel);
        log.error("通道{}断开ip:port【{}】",NettyConstant.getChannelId(channel), cp);
        statusInfo();
    }

    public void removeSnChannel(Channel channel) {
//        NettyConstant.removeChannel(channel);
    }
}
